/*
 * adc.c
 *
 * Created: 6/18/2013 6:53:08 PM
 *  Author: Tim
 */ 


#include <avr/io.h>
#include <avr/interrupt.h>
#include <math.h>

#include "adc.h"
#include "../allocations.h"
#include "../../board/board.h"
#include "../../packets/structs/adcPacketStructs.h"
#include "../tmr/tmr.h"


volatile uint8_t currentChannel = 0;


void adcSetup()
{
	//enable the peripheral clock for the adc module(s)
	prEnable(ADC_PR);
	
	ADCA.CALL = ReadCalibrationByte( offsetof(NVM_PROD_SIGNATURES_t, ADCACAL0) );
	ADCA.CALH = ReadCalibrationByte( offsetof(NVM_PROD_SIGNATURES_t, ADCACAL1) );
	//delay of analog startup
	MCU.ANAINIT = MCU_STARTUPDLYA0_bm | MCU_STARTUPDLYA1_bm;
	
	//select the 2.5V external reference
	ADCA.REFCTRL	=	ADC_REFSEL_AREFB_gc		;
	
	//ADC prescaler selection
	ADCA.PRESCALER = ADC_PRESCALER_DIV32_gc;
	
	//setup the ADCA configuration
	ADCA.CTRLB		=
//	ADC_IMPMODE_bm			|	//high impedance enable, since the board uses op-amps for the front end
	ADC_CURRLIMIT_NO_gc		|	//eliminate the current limit in order to max out the ADC speed
	ADC_CONMODE_bm			|	//sets up the conversions for signed mode
	ADC_FREERUN_bm			|	//sets up the adc to collect data autonomously
	ADC_RESOLUTION_12BIT_gc	;	//sets adc to have 12 bit resolution with right adjustment (LSB)
	
	//tell the ADC to speep all channels 0-3 automatically
	ADCA.EVCTRL = ADC_SWEEP_0123_gc;
	
	/**************Channel setups***************/
	
	
	//preliminary gain and input mode selection
	
	ADCA.CH0.CTRL	 = ADC_CH_GAIN_2X_gc | ADC_CH_INPUTMODE_DIFFWGAIN_gc;

	ADCA.CH1.CTRL	 = ADC_CH_GAIN_2X_gc | ADC_CH_INPUTMODE_DIFFWGAIN_gc;

	ADCA.CH2.CTRL	 = ADC_CH_GAIN_2X_gc | ADC_CH_INPUTMODE_DIFFWGAIN_gc;

	ADCA.CH3.CTRL	 = ADC_CH_GAIN_2X_gc | ADC_CH_INPUTMODE_DIFFWGAIN_gc;

	// mux positions
	
	ADCA.CH2.MUXCTRL =	ADC_CH_MUXPOS_PIN3_gc	|
	ADC_CH_MUXNEG_PIN7_gc	;
	
	ADCA.CH3.MUXCTRL =	ADC_CH_MUXPOS_PIN0_gc	|
	ADC_CH_MUXNEG_PIN4_gc	;
	
	ADCA.CH1.MUXCTRL =	ADC_CH_MUXPOS_PIN2_gc	|
	ADC_CH_MUXNEG_PIN6_gc	;
	
	ADCA.CH0.MUXCTRL =	ADC_CH_MUXPOS_PIN1_gc	|
	ADC_CH_MUXNEG_PIN5_gc	;
	
	ADCA.CH0.CTRL |= ADC_CH_START_bm;
	ADCA.CH1.CTRL |= ADC_CH_START_bm;
	ADCA.CH2.CTRL |= ADC_CH_START_bm;
	ADCA.CH3.CTRL |= ADC_CH_START_bm;
	
	ADCA.CTRLA |= ADC_ENABLE_bm;

	//set the appropriate interrupt levels at the global scope
	PMIC.CTRL |= PMIC_LOLVLEN_bm | PMIC_RREN_bm;
	
}

int16_t filterData(int16_t *data)
{
	int32_t sum = 0;
	uint8_t inc;
	
	for(inc=0;inc<16;inc++)
	{
		sum+=data[inc];
	}

	if (sum < 0)
	{
		sum = sum>>2;
		sum |= 0xC0000000;
	}
	else
	{
		sum = sum>>2;
	}	
	return (int16_t) sum;
}

void adcSetGain(ACHM_t achm, uint8_t gain)
{
		
	if(achm & ADC_CH0_bp)
	{
		ADCA.CH0.CTRL &= ~(ADC_CH_GAIN_gm);
		ADCA.CH0.CTRL |= (gain<<ADC_CH_GAIN_gp);
	}
	if(achm & ADC_CH1_bp)
	{
		ADCA.CH1.CTRL &= ~(ADC_CH_GAIN_gm);
		ADCA.CH1.CTRL |= (gain<<ADC_CH_GAIN_gp);
	}
	if(achm & ADC_CH2_bp)
	{
		ADCA.CH2.CTRL &= ~(ADC_CH_GAIN_gm);
		ADCA.CH2.CTRL |= (gain<<ADC_CH_GAIN_gp);
	}
	if(achm & ADC_CH3_bp)
	{
		ADCA.CH3.CTRL &= ~(ADC_CH_GAIN_gm);
		ADCA.CH3.CTRL |= (gain<<ADC_CH_GAIN_gp);
	}
}


ISR(ADCA_CH0_vect)
{
	adcCh0_data[adcCnt[0].CNT++] = ADCA.CH0.RES;
}
ISR(ADCA_CH1_vect)
{
	adcCh1_data[adcCnt[1].CNT++] = ADCA.CH1.RES;
}
ISR(ADCA_CH2_vect)
{
	adcCh2_data[adcCnt[2].CNT++] = ADCA.CH2.RES;
}
ISR(ADCA_CH3_vect)
{
	adcCh3_data[adcCnt[3].CNT++] = ADCA.CH3.RES;
}
